package com.chapter.sample.processor;

import com.chapter.sample.advice.MyAdvice;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MockAopBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {

        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //目的：对UserServiceImpl中的show1和show2方法进行增强，增强方法存在与MyAdvice中
        //问题1：筛选，UserServiceImpl 或 筛选service.impl包下的类的所有方法都进行增强，
        //问题2: MyAdvice怎么获取到？解决方案：从Spring容器中获取MyAdvice

        if (bean.getClass().getPackage().getName().equals("com.chapter.sample.service.impl")) {
            //生成当前bean的Proxy对象
            Object beanPoxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(),
                    bean.getClass().getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            MyAdvice myAdvice = applicationContext.getBean(MyAdvice.class);

                            //执行正确对象的before方法
                            myAdvice.beforeAdvice();

                            //执行目标对象的目标方法
                            Object invoke = method.invoke(bean, args);

                            //执行正确对象的after方法
                            myAdvice.afterAdvice();
                            return invoke;
                        }
                    });
            return beanPoxy;
        }
        return bean;
    }

    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
